/**
 * Copyright (c) 2000-2012 Liferay, Inc. All rights reserved.
 *
 * This library is free software; you can redistribute it and/or modify it under
 * the terms of the GNU Lesser General Public License as published by the Free
 * Software Foundation; either version 2.1 of the License, or (at your option)
 * any later version.
 *
 * This library is distributed in the hope that it will be useful, but WITHOUT
 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
 * FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more
 * details.
 */

package com.mad.bikepony.service.impl;

import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.net.HttpURLConnection;
import java.net.MalformedURLException;
import java.net.URL;
import java.text.DateFormat;
import java.util.Calendar;
import java.util.Date;
import java.util.GregorianCalendar;
import java.util.HashMap;
import java.util.LinkedList;
import java.util.List;
import java.util.Map;
import java.util.Map.Entry;

import javax.mail.internet.InternetAddress;

import com.liferay.mail.service.MailServiceUtil;
import com.liferay.portal.kernel.dao.orm.QueryUtil;
import com.liferay.portal.kernel.exception.PortalException;
import com.liferay.portal.kernel.exception.SystemException;
import com.liferay.portal.kernel.json.JSONArray;
import com.liferay.portal.kernel.json.JSONFactoryUtil;
import com.liferay.portal.kernel.json.JSONObject;
import com.liferay.portal.kernel.jsonwebservice.JSONWebService;
import com.liferay.portal.kernel.mail.MailMessage;
import com.liferay.portal.kernel.util.DateFormatFactoryUtil;
import com.liferay.portal.kernel.util.DateUtil;
import com.liferay.portal.kernel.util.HttpUtil;
import com.liferay.portal.kernel.util.LocaleUtil;
import com.liferay.portal.kernel.util.TimeZoneUtil;
import com.mad.bikepony.NoSuchAgentException;
import com.mad.bikepony.NoSuchDeliveryException;
import com.mad.bikepony.model.Agent;
import com.mad.bikepony.model.AgentState;
import com.mad.bikepony.model.Delivery;
import com.mad.bikepony.model.DeliveryState;
import com.mad.bikepony.model.DestinationEntry;
import com.mad.bikepony.model.Question;
import com.mad.bikepony.model.QuestionResponse;
import com.mad.bikepony.model.ResultMessage;
import com.mad.bikepony.model.impl.QuestionResponseImpl;
import com.mad.bikepony.portlet.StatusCode;
import com.mad.bikepony.service.QuestionLocalServiceUtil;
import com.mad.bikepony.service.base.AgentServiceBaseImpl;

/**
 * The implementation of the agent remote service.
 *
 * <p>
 * All custom service methods should be put in this class. Whenever methods are added, rerun ServiceBuilder to copy their definitions into the {@link com.mad.bikepony.service.AgentService} interface.
 *
 * <p>
 * This is a remote service. Methods of this service are expected to have security checks based on the propagated JAAS credentials because this service can be accessed remotely.
 * </p>
 *
 * @author nicola
 * @see com.mad.bikepony.service.base.AgentServiceBaseImpl
 * @see com.mad.bikepony.service.AgentServiceUtil
 */
public class AgentServiceImpl extends AgentServiceBaseImpl {
	/*
	 * NOTE FOR DEVELOPERS:
	 *
	 * Never reference this interface directly. Always use {@link com.mad.bikepony.service.AgentServiceUtil} to access the agent remote service.
	 */
	private static final int MAXIMUM_WAYPOINTS_PER_REQUEST = 8;
	private static final int DELIVERY_POSITION = 1;
	private static final int PICKUP_POISTION = 0;
	@JSONWebService(method="GET",value="/agent/update-position")
	public ResultMessage updatePosition(long agentId,double latitude,double longitude,List<String> destinations)
	{
		ResultMessage message = new ResultMessage();
		try {
			Agent agent = agentLocalService.getAgent(agentId);
			agent.setLastPos_latitude(latitude);
			agent.setLastPos_longitude(longitude);
			agent.setLastUpdate(System.currentTimeMillis());
			agent = agentLocalService.updateAgent(agent,true);
			if(destinations!=null && !destinations.isEmpty())
			{
				LinkedList<DestinationEntry> backedOrderedList = new LinkedList<DestinationEntry>();
				/* 
				 * the destinations map represents the order in which the list has to be approved :
				 * each item in the list to check corresponds either to a pickup or to a delivery
				 * Iterating over the list , we build this map in which for each DeliveryId we register the order in which we
				 * find a delivery task or a pickup task , so that we can easily manage if a pickup is after a delivery for the same deliveryId
				 */
				Map<Long,boolean[]>destinationsMap = new HashMap<Long, boolean[]>();
				
				for(int i=0;i<destinations.size();i++)
				{
					String destination = destinations.get(i);
					int paramLength=0;
					/*the res String array corresponds to [ deliveryId - pickup:yes/no] */
					String[] res= null;
					if(destination!=null)
					{
						res = destination.split("-");
						paramLength= res.length;
					}
					if(paramLength!=2)
					{
						message.setStatusCode(StatusCode.STATUS_ERR_UNKNOWN.getStatusCode());
						message.setMessage("syntax error. Malformed parameters format");
						break;
					}else
					{
						/*initialize the status message to a OK result*/
						message.setStatusCode(StatusCode.STATUS_OK.getStatusCode());
						message.setMessage("OK");
						try
						{
							Long id = Long.parseLong(res[0]);
							if(!res[1].toLowerCase().matches("true|false"))
								throw new Exception("malformed boolean value");
							boolean type = Boolean.parseBoolean(res[1]);
							if(!destinationsMap.containsKey(id))
							{
								/*this is the first item we encounter this delivery Id, thus we create the container object*/
								DestinationEntry dEntry = new DestinationEntry();
								dEntry.setId(id);
								
								/*type will contain the 2 tasks belonging to a Parcel activity : the 0 is the pickup and the 1 is the delivery*/
								boolean[] types=new boolean[]{false,false};
								if(type==false)
								{
									/*if the current Entry has value false , this task is a delivery one , thus set the corresponding value in the array*/
									types[DELIVERY_POSITION]=true;
									dEntry.setDelivery(true);
								}else
								{
									/*this task is a pickup task*/
									types[PICKUP_POISTION]=true;
									dEntry.setPickUp(true);
								}	
								
								destinationsMap.put(id, types);
								backedOrderedList.add(dEntry);
							}else
							{
								// the element is present inside the list -> perform sanity checks
								boolean []types = destinationsMap.get(id);
								if(types[PICKUP_POISTION] && types[DELIVERY_POSITION])
								{
									// error because at most twice 
									message.setStatusCode(StatusCode.STATUS_ERR_REORDERING_NOT_ALLOWED.getStatusCode());
									message.setMessage("duplicate deliveries. They must appear at most twice");
									JSONObject jsonObject = JSONFactoryUtil.createJSONObject();
									jsonObject.put("wrong_delivery_id", id);
									jsonObject.put("type",0);
									message.setData(jsonObject);
									break;
								}else if(types[DELIVERY_POSITION] && type)
								{
									// error because pickup after delivery is not allowed
									message.setStatusCode(StatusCode.STATUS_ERR_REORDERING_NOT_ALLOWED.getStatusCode());
									message.setMessage("pickup after delivery is not allowed");
									JSONObject jsonObject = JSONFactoryUtil.createJSONObject();
									jsonObject.put("wrong_delivery_id", id);
									jsonObject.put("type",1);
									message.setData(jsonObject);
									break;
								}else if(types[DELIVERY_POSITION] && !type)
								{
									// error because delivery duplicates are not allowed
									message.setStatusCode(StatusCode.STATUS_ERR_REORDERING_NOT_ALLOWED.getStatusCode());
									message.setMessage("delivery duplicates are not allowed");
									JSONObject jsonObject = JSONFactoryUtil.createJSONObject();
									jsonObject.put("wrong_delivery_id", id);
									jsonObject.put("type",1);
									message.setData(jsonObject);
									break;
								}else if(types[PICKUP_POISTION] && type)
								{
									// error because pickUp duplicates are not allowed
									message.setStatusCode(StatusCode.STATUS_ERR_REORDERING_NOT_ALLOWED.getStatusCode());
									message.setMessage("pickup duplicates are not allowed");
									JSONObject jsonObject = JSONFactoryUtil.createJSONObject();
									jsonObject.put("wrong_delivery_id", id);
									jsonObject.put("type",0);
									message.setData(jsonObject);
									break;
								}else
								{
									/* 
									 * at this point all the sanity checks are passed and we add the Task entry inside our backed collections
									 * after having updates the DTO object
									 */
									DestinationEntry dEntry = new DestinationEntry();
									dEntry.setId(id);
									if(type)
									{
										types[PICKUP_POISTION]=true;
										dEntry.setPickUp(true);
									}else if(!type)
									{
										types[DELIVERY_POSITION]=true;
										dEntry.setDelivery(true);
									}
									backedOrderedList.add(dEntry);
								}
							}
						}catch(Exception e)
						{
							e.printStackTrace();
							message.setStatusCode(-1);
							message.setMessage("syntax error. Malformed parameters format");
							break;
						}
					}
				}
				/*something failed and we don't need to go further in the elaboration*/
				if(message.getStatusCode()!=StatusCode.STATUS_OK.getStatusCode())
					return message;
				
				
				// check database status and correctness
				Map<Long,Delivery> deliveriesCachedObjects = new HashMap<Long, Delivery>();
				for(Entry<Long, boolean[]> entry : destinationsMap.entrySet())
				{
					boolean[] types = entry.getValue();
					if(types[PICKUP_POISTION] && !types[DELIVERY_POSITION])
					{
						//error the delivery entry must be set to DELIVERY
						message.setStatusCode(StatusCode.STATUS_ERR_REORDERING_NOT_ALLOWED.getStatusCode());
						message.setMessage("deliveryId "+entry.getKey()+" : A pickup must be followed by a delivery");
						break;
					}else
					{
						Delivery delivery = deliveryPersistence.findByDeliveryIdAndAgentId(entry.getKey(),agentId);
						deliveriesCachedObjects.put(entry.getKey(), delivery);
						if(!types[PICKUP_POISTION] && types[DELIVERY_POSITION])
						{
						// database check for right state
							if(DeliveryState.fromState(delivery.getState())!= DeliveryState.BEING_DELIVERED)
							{
								// error
								message.setStatusCode(StatusCode.STATUS_ERR_REORDERING_NOT_ALLOWED.getStatusCode());
								message.setMessage("deliveryId "+entry.getKey()+" : A delivery can be applied only to \"Being delivered\" parcels");
								break;
							}
						}else
						{
							// the delivery entry has both delivery and pickup
							if(DeliveryState.fromState(delivery.getState())!= DeliveryState.WAITING_FOR_PICKUP)
							{
								// error
								message.setStatusCode(StatusCode.STATUS_ERR_REORDERING_NOT_ALLOWED.getStatusCode());
								message.setMessage("deliveryId "+entry.getKey()+" :  pickup and a delivery can be applied only to \"Waiting for pickup\" parcels");
								break;
							}
						}
					}
				}
				/*an error occured ,ths we break the elaboration*/
				if(message.getStatusCode()!=StatusCode.STATUS_OK.getStatusCode())
					return message;
				
				try{
					
					/*start preparing the URL in order to call the GOOGLE direction API fro building the new route with estimated times*/
					String googleServiceUrl = "http://maps.googleapis.com/maps/api/directions/json?";
					String startingPosition =String.valueOf(latitude).replaceAll(",", ".")+","+String.valueOf(longitude).replaceAll(",", ".");
					long startingTime= DateUtil.newTime();
					int chunkStartPos= 0;
					int chunkSize=0;
					
					boolean error=false;
					while(chunkStartPos<backedOrderedList.size())
					{
						String urlString = HttpUtil.addParameter(googleServiceUrl, "origin", startingPosition);
						if(startingTime!=-1)
						{
							urlString = HttpUtil.addParameter(urlString, "departure_time", String.valueOf(startingTime/100));
						}
						StringBuilder wayPoints = new StringBuilder();
						String wayPointsSeparator ="|";
						/*init the chunk size*/
						chunkSize=0;
						/*a maximum of MAXIMUM_WAYPOINTS_PER_REQUEST can be put in a query*/
						for(int i=chunkStartPos; i<backedOrderedList.size() && chunkSize< MAXIMUM_WAYPOINTS_PER_REQUEST ;i++){
							DestinationEntry dEntry = backedOrderedList.get(i);
							Delivery del = deliveriesCachedObjects.get(dEntry.getId());
							String wayPointAddress;
							if(dEntry.isDelivery())
							{
								wayPointAddress = del.getRecipientAddress();
							}else
								wayPointAddress = del.getSenderAddress();
							
							if(chunkSize< MAXIMUM_WAYPOINTS_PER_REQUEST-1)
								wayPoints.append(wayPointAddress).append(wayPointsSeparator);
							else
								urlString = HttpUtil.addParameter(urlString,"destination", wayPointAddress);
							
							chunkSize++;
						}
						urlString = HttpUtil.addParameter(urlString, "waypoints", wayPoints.toString());
						urlString = HttpUtil.addParameter(urlString, "mode", "bycicling");
						urlString = HttpUtil.addParameter(urlString, "sensor", "false");
						URL url = new URL(urlString);
						HttpURLConnection connection = (HttpURLConnection)url.openConnection();
						InputStream is = connection.getInputStream();
						if(is!=null){
							BufferedReader br = new BufferedReader(new InputStreamReader(is));
							StringBuilder jsonresponseBuilder = new StringBuilder();
							String line=null;
							while((line= br.readLine())!=null)
								jsonresponseBuilder.append(line);
							
							JSONObject object = JSONFactoryUtil.createJSONObject(jsonresponseBuilder.toString());
							if(!object.getString("status").equals("OK")){
								message.setStatusCode(StatusCode.STATUS_ERR_REORDERING_NOT_ALLOWED.getStatusCode());
								message.setMessage("unable to redefine the routes for the new list");
								error = true;
								break;
							}
							
							JSONArray routes = object.getJSONArray("routes");
							if(routes.length()==1)
							{
								JSONArray legs = routes.getJSONObject(0).getJSONArray("legs");
								int receivedLegs = legs.length();
								if(receivedLegs!=chunkSize)
								{
									message.setStatusCode(StatusCode.STATUS_ERR_REORDERING_NOT_ALLOWED.getStatusCode());
									message.setMessage("unable to redfine the routes for the new list");
									error = true;
									break;
								}
								long expectedTime = startingTime;
								for(int i=0;i<legs.length();i++)
								{
									int duration = legs.getJSONObject(i).getJSONObject("duration").getInt("value");// in seconds
									DestinationEntry dentry = backedOrderedList.get(chunkStartPos+i);
									Delivery delivery = deliveriesCachedObjects.get(dentry.getId());
									expectedTime+=duration*1000;
									if(dentry.isDelivery())
									{
										delivery.setEstimatedDeliveryTime(expectedTime);
									}else
									{
										delivery.setEstimatedPickupTime(expectedTime);
									}
								}
								
								chunkStartPos+=chunkSize;
								DestinationEntry nextStartLeg = backedOrderedList.get(chunkStartPos-1);
								Delivery d = deliveriesCachedObjects.get(nextStartLeg.getId());
								if(nextStartLeg.isDelivery())
								{
									startingPosition = d.getRecipientAddress();
									startingTime = d.getEstimatedDeliveryTime();
								}
								else
								{
									startingPosition = d.getSenderAddress();
									startingTime = d.getEstimatedPickupTime();
								}
							}else
							{
								message.setStatusCode(StatusCode.STATUS_ERR_REORDERING_NOT_ALLOWED.getStatusCode());
								message.setMessage("unable to redfine the routes for the new list");
								error = true;
								break;
							}
							is.close();
						}
					}
					if(error)
					{
						return message;
					}
					
					
					
					/*send email messages*/
					try
					{
						InternetAddress fromAddress = new InternetAddress("admin@bikePony.it");
						DateFormat df = DateFormatFactoryUtil.getDateTime(LocaleUtil.getDefault(), TimeZoneUtil.getDefault());
						for(Delivery delivery : deliveriesCachedObjects.values())
						{
							delivery = deliveryPersistence.update(delivery, false);
							
							/*TODO send the email to sender and recipient about the changed times*/
							MailMessage mm = new MailMessage();
							mm.setFrom(fromAddress);
							mm.setTo(new InternetAddress(delivery.getSenderEmail()));
							mm.setSubject("Bike Pony service - update parcel status information");
							JSONObject senderAdditionalInfo = JSONFactoryUtil.createJSONObject(delivery.getSenderAdditionalInfo());
							mm.setBody("Dear sig. <b>"+senderAdditionalInfo.getString("name")+" "+senderAdditionalInfo.getString("surnmame")+"</b>," +
									"<br/>Your parcel' status ,identified by the tracking-code <h3 color=\"green\">"+delivery.getTrackingCode()+"</h3>, is changed.<br/> Please check at our <a href=\"http://localhost:8080/web/guest/tracking\">website</a> the new status of your parcel." +
									"<br/>The newly estimated pickup time is: "+df.format(new Date(delivery.getEstimatedPickupTime()))+
									"<br/><br/>Thank you to have chosen our service." +
									"<br/>Best regards, the administrative office of BikePony");
							mm.setHTMLFormat(true);
							MailServiceUtil.sendEmail(mm);
							
							MailMessage mm1 = new MailMessage();
							mm1.setFrom(fromAddress);
							mm1.setTo(new InternetAddress(delivery.getRecipientEmail()));
							mm1.setSubject("Bike Pony service - update parcel status information");
							JSONObject recipientAdditionalInfo = JSONFactoryUtil.createJSONObject(delivery.getRecipientAdditionalInfo());
							mm1.setBody("Dear sig. <b>"+recipientAdditionalInfo.getString("name")+" "+recipientAdditionalInfo.getString("surname")+"</b>," +
									"<br/>Your parcel' status ,identified by the delivery-code <h3 color=\"green\">"+delivery.getDeliveryCode()+"</h3>, is changed." +
									"<br>The newly estimated delivery time is: "+df.format(new Date(delivery.getEstimatedDeliveryTime()))+
									"<br/><br/>Thank you to have chosen our service." +
									"<br/>Best regards, the administrative office of BikePony");
							mm1.setHTMLFormat(true);
							MailServiceUtil.sendEmail(mm1);
							
						}
					}catch(Exception e)
					{
						e.printStackTrace();
					}
					//String encodedUrl = HttpUtil.encodeURL(parameters.toString());
				} catch (MalformedURLException e) {
					e.printStackTrace();
				}
				catch (IOException e) {
					e.printStackTrace();
				}
			}
				
			List<Delivery> deliveries = deliveryPersistence.findByDeliveryStateAndAgentId(agentId, new int[]{DeliveryState.BEING_DELIVERED.toState(),DeliveryState.WAITING_FOR_PICKUP.toState()});
			JSONArray deliveriesJson = JSONFactoryUtil.createJSONArray();
			for(Delivery delivery:deliveries)
			{
				JSONObject obj = JSONFactoryUtil.createJSONObject();
				obj.put("delivery-id", delivery.getDeliveryId());
				obj.put("sender-address", delivery.getSenderAddress());
				obj.put("pickup-estimated-time", delivery.getEstimatedPickupTime());
				obj.put("recipient-address", delivery.getRecipientAddress());
				obj.put("delivery-estimated-time", delivery.getEstimatedDeliveryTime());
				/*the state should be taken from an object contained into a library shared with the client*/
				obj.put("state", delivery.getState());
				obj.put("sender-additional-info", delivery.getSenderAdditionalInfo());
				obj.put("recipient-additional-info", delivery.getRecipientAdditionalInfo());
				deliveriesJson.put(obj);
			}
			JSONObject resultData = JSONFactoryUtil.createJSONObject();
			resultData.put("deliveries", deliveriesJson);
			message.setData(resultData);
			message.setStatusCode(StatusCode.STATUS_OK.getStatusCode());
			message.setMessage("succesfully updated");
			
		} catch (PortalException e) {
			e.printStackTrace();
			message.setStatusCode(StatusCode.STATUS_ERR_UNKNOWN.getStatusCode());
			message.setMessage("an error occurred");
		} catch (SystemException e) {
			e.printStackTrace();
			message.setStatusCode(StatusCode.STATUS_ERR_UNKNOWN.getStatusCode());
			message.setMessage("an error occurred");
		}
		return message;
			 
	}
	
	@JSONWebService(method="POST",value="/agent/login")
	public ResultMessage loginAgent(long agentId,String password)
	{
		ResultMessage message = new ResultMessage();
		
		try {
			Agent agent = agentPersistence.findByAgentIdAndPassword(agentId, password);
			if(agent.getStatus()== AgentState.STATUS_LOGGED_IN.getState())
			{
				message.setMessage("you are already logged in");
				message.setStatusCode(StatusCode.STATUS_ERR_ALREADY_LOGGED_IN.getStatusCode());
			}else
			{
				agent.setStatus(AgentState.STATUS_LOGGED_IN.getState());
				agentLocalService.updateAgent(agent,true);
				message.setStatusCode(StatusCode.STATUS_OK.getStatusCode());
				message.setMessage("agent "+agentId+" succesfully logged in");
				List<Question> questions = QuestionLocalServiceUtil.getQuestions(QueryUtil.ALL_POS, QueryUtil.ALL_POS);
				JSONArray array  = JSONFactoryUtil.createJSONArray();
				
				for(Question question:questions)
				{
					JSONObject jsonQuestion = JSONFactoryUtil.createJSONObject();
					jsonQuestion.put("text", question.getText());
					jsonQuestion.put("id", question.getQuestionId());
					array.put(jsonQuestion);
				}
				JSONObject obj = JSONFactoryUtil.createJSONObject();
				obj.put("questions", array);
				message.setData(obj);
			}
		} catch (NoSuchAgentException e) {
			message.setStatusCode(StatusCode.STATUS_ERR_INVALID_CREDENTIALS.getStatusCode());
			message.setMessage("incorrect agentId or password");
			e.printStackTrace();
		} catch (SystemException e) {
			message.setStatusCode(StatusCode.STATUS_ERR_UNKNOWN.getStatusCode());
			message.setMessage("an error occurred during login process");
			e.printStackTrace();
		}
		return message;
	}
	@JSONWebService("/agent/logoff")
	public ResultMessage logoffAgent(long agentId)
	{
		ResultMessage message = new ResultMessage();
		
		try {
			Agent agent = agentPersistence.findByPrimaryKey(agentId);
			if(agent.getStatus() == AgentState.STATUS_LOGGED_OFF.getState())
			{
				message.setMessage("you are already logged off");
				message.setStatusCode(StatusCode.STATUS_ERR_ALREADY_LOGGED_OFF.getStatusCode());
			}else
			{
				int pendingTasksForAgent = deliveryPersistence.countByDeliveryStateAndAgentId(agentId, new int[]{DeliveryState.WAITING_FOR_PICKUP.toState(),DeliveryState.BEING_DELIVERED.toState()});
				if(pendingTasksForAgent>0)
				{
					// set the agent status to "not send any more task"
					agent.setStatus(AgentState.STATUS_PENDING.getState());
					message.setStatusCode(StatusCode.STATUS_ERR_PENDING_TASKS.getStatusCode());
					message.setMessage("In order to log off you must complete all pending tasks. No more tasks will be assigned to you");
					
				}else
				{
					agent.setStatus(AgentState.STATUS_LOGGED_OFF.getState());
					message.setStatusCode(StatusCode.STATUS_OK.getStatusCode());
					message.setMessage("agent "+agentId+" succesfully logged off");
				}
				agentLocalService.updateAgent(agent,true);
			}
		} catch (NoSuchAgentException e) {
			message.setStatusCode(StatusCode.STATUS_AGENT_NOT_KNOWN.getStatusCode());
			message.setMessage("incorrect agentId");
			e.printStackTrace();
		} catch (SystemException e) {
			message.setStatusCode(StatusCode.STATUS_ERR_UNKNOWN.getStatusCode());
			message.setMessage("an error occurred during login process");
			e.printStackTrace();
		}
		return message;
	}
	
	@JSONWebService(method="POST", value="/agent/verify-pickup")
	public ResultMessage verifypickupAgent(long agentId, long deliveryId, String trackingCode )
	{
		ResultMessage message = new ResultMessage();
		try {
			
				Delivery delivery = deliveryPersistence.findByDeliveryIdAndTrackingCodeAndAgentId(deliveryId, trackingCode, agentId);
				//FIXME: set enumeration for states 
				delivery.setState(DeliveryState.BEING_DELIVERED.toState());
				
				Calendar cal = GregorianCalendar.getInstance();
				delivery.setPickupTimestamp(cal.getTimeInMillis());
				
				deliveryLocalService.updateDelivery(delivery, true); 
				
				message.setStatusCode(StatusCode.STATUS_OK.getStatusCode());
				message.setMessage("success");
				
		} catch (NoSuchDeliveryException e) {
			message.setStatusCode(StatusCode.STATUS_TRACKING_CODE_INVALID.getStatusCode());
			message.setMessage("incorrect tracking code");
			e.printStackTrace();
		} catch (SystemException e) {
			message.setStatusCode(StatusCode.STATUS_ERR_UNKNOWN.getStatusCode());
			message.setMessage("an error occurred during verify process");
			e.printStackTrace();
		}
		
		return message;
	}
	
	//upon verify delivery code if the delivery code is correct set of questions will be sent back as response. 
	
	@JSONWebService(method="POST", value="/agent/verify-delivery")
	public ResultMessage verifydeliveryAgent(long agentId, long deliveryId, String deliveryCode )
	{
		System.out.println("signature ");
		System.out.println(deliveryCode);
		ResultMessage message = new ResultMessage();
		try{
			Delivery delivery = deliveryPersistence.findByDeliveryIdAndDeliveryCodeAndAgentId(deliveryId, deliveryCode, agentId);
			//FIXME: set enumeration for states 
			delivery.setState(DeliveryState.DELIVERED.toState());
			
			Calendar cal = GregorianCalendar.getInstance();
			delivery.setDeliveryTimestamp(cal.getTimeInMillis());
			
			
			deliveryLocalService.updateDelivery(delivery, true); 
			
			message.setStatusCode(StatusCode.STATUS_OK.getStatusCode());
			message.setMessage("success");
			
		} catch (NoSuchDeliveryException e) {
			message.setStatusCode(StatusCode.STATUS_DELIVERY_CODE_INVALID.getStatusCode());
			message.setMessage("Please check the data passed.");
			e.printStackTrace();
		} catch (SystemException e) {
			message.setStatusCode(StatusCode.STATUS_ERR_UNKNOWN.getStatusCode());
			message.setMessage("an error occurred during verify process");
			e.printStackTrace();
		}
		
		
		return message;
	}
	
	@JSONWebService(method="POST", value="/agent/submit-signature")
	public ResultMessage submitsignatureAgent(long agentId, long deliveryId, String recipientSignature, List<String> answers )
	{
		recipientSignature = recipientSignature.replaceAll(" ", "+").replaceAll("_", "/");
		//System.out.println("signature");
		//System.out.println(recipientSignature);
		ResultMessage message = new ResultMessage();
		try
		{
			Delivery delivery = deliveryPersistence.findByDeliveryIdAndAgentId(deliveryId, agentId);
			
			delivery.setRecipientSignature(recipientSignature);
			 
			if(answers != null)
			{
				for(int i=0;i<answers.size();i++)
				{
					String answer = answers.get(i);
					int paramLength=0;
					String[] res= null;
					if(answer!=null)
					{
						res = answer.split("-");
						paramLength= res.length;
					}
					if(paramLength!=2)
					{
						message.setStatusCode(-1);
						message.setMessage("syntax error. Malformed parameters format for answers");
						return message;//TODO: update this behaviour and should return from only at the end try break;
					}
					else
					{
						
						Long questionId =  Long.parseLong(res[0]);
						int vote =  Integer.parseInt(res[1]);//vote
						
						QuestionResponse testQuestio = new QuestionResponseImpl();
						testQuestio.setQuestionId(questionId);
						testQuestio.setVote(vote);
						
						questionResponsePersistence.update(testQuestio, false );
						
					}
				}
			}
			
			deliveryLocalService.updateDelivery(delivery, true); 
			
			message.setStatusCode(0);
			message.setMessage("success");
			
		}
		catch (NoSuchDeliveryException e) {
			message.setStatusCode(-1);
			message.setMessage("Please check the data passed.");
			e.printStackTrace();
		} catch (SystemException e) {
			message.setStatusCode(-1);
			message.setMessage("an error occurred during verify process");
			e.printStackTrace();
		}
		return message;
	}
	
	
	
}